watch2gether.ts ➔ init   B
last analyzed

Complexity

Conditions 6

Size

Total Lines 41
Code Lines 35

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 35
dl 0
loc 41
rs 8.1066
c 0
b 0
f 0
1
import * as core from '../utils/aniwatchCore';
2
import { v4 as uuidv4 } from 'uuid';
3
import { getGlobalConfiguration, SETTINGS_w2gDisplayCharacterCounter, SETTINGS_w2gAutotoggleHide, SETTINGS_w2gAutoscrollToUnseen } from '../configuration/configuration';
4
import { assigned } from '../utils/helpers';
5
import { findPlayerElement } from "../enhancements/anilyr";
6
7
const PLAYER_ID = 'wPlayer';
8
let hidden: boolean;
9
10
export function init(): void {
11
    getGlobalConfiguration().getProperty(SETTINGS_w2gDisplayCharacterCounter, value => {
12
        if (value) {
13
            core.runAfterLoad(() => {
14
                manipulateChatInput();
15
            }, "^/watch2gether/.*$");
16
17
            core.runAfterLocationChange(() => {
18
                manipulateChatInput();
19
            }, "^/watch2gether/.*$");
20
        }
21
    });
22
23
    getGlobalConfiguration().getProperty(SETTINGS_w2gAutotoggleHide, value => {
24
        if (value) {
25
            core.runAfterLoad(() => {
26
                addAutohideListener();
27
            }, "^/watch2gether/.*$");
28
29
            core.runAfterLocationChange(() => {
30
                addAutohideListener();
31
            }, "^/watch2gether/.*$");
32
        }
33
    });
34
35
    getGlobalConfiguration().getProperty(SETTINGS_w2gAutoscrollToUnseen, value => {
36
        if (value) {
37
            core.runAfterLoad(() => {
38
                let element = findSearchResults();
39
                if (assigned(element)) {
40
                    scrollSearchResults(element);
41
                }
42
            }, "^/watch2gether/.*$");
43
44
            core.runAfterLocationChange(() => {
45
                let element = findSearchResults();
46
                if (assigned(element)) {
47
                    scrollSearchResults(element);
48
                }
49
            }, "^/watch2gether/.*$");
50
        }
51
    });
52
}
53
54
function manipulateChatInput(): void {
55
    let textarea = document.querySelector('.chat-input textarea') as HTMLTextAreaElement;
56
57
    // avoid duplicate registration
58
    if (assigned(textarea.dataset.charCounterId)) {
59
        return;
60
    }
61
62
    addCharCounter(textarea);
63
}
64
65
function addCharCounter(textarea: HTMLTextAreaElement): void {
66
    let chatDiv = textarea.parentElement.parentElement; // div with chat input and controls
67
    let controlRow = chatDiv.children[1]; // row with controls
68
    let btn = controlRow.querySelector('button'); // find send button
69
70
    let charCounterSpan = document.createElement('span'); // create span for counter
71
    charCounterSpan.classList.add('awp-w2g-chatCounter');
72
73
    // id and "connection"
74
    let counterId = `awp-${uuidv4()}`
75
    charCounterSpan.id = counterId;
76
    textarea.dataset.charCounterId = counterId;
77
78
    btn.parentElement.insertBefore(charCounterSpan, btn); // and insert in front of the button
79
    updateCharCounter(textarea, charCounterSpan);
80
81
    textarea.addEventListener('keyup', () => {
82
        updateCharCounter(textarea, charCounterSpan)
83
    });
84
}
85
86
function updateCharCounter(textarea: HTMLTextAreaElement, charCounterSpan: HTMLSpanElement): void {
87
    const SHAKE_CLASS = 'awp-w2g-chatCounter-max';
88
89
    let current = textarea.value.length;
90
    let max = textarea.maxLength;
91
92
    charCounterSpan.innerText = `${current} / ${max}`;
93
94
    // animation if at max
95
    if (current >= max && !charCounterSpan.classList.contains(SHAKE_CLASS)) {
96
        charCounterSpan.classList.add(SHAKE_CLASS);
97
98
        // remove css class after animation finished, so it can be restarted again
99
        setTimeout(() => {
100
            charCounterSpan.classList.remove(SHAKE_CLASS);
101
        }, 200);
102
    }
103
}
104
105
function addAutohideListener(): void {
106
    let playerElement = findPlayerElement(PLAYER_ID);
107
    let hideButton: HTMLButtonElement = document.getElementsByClassName('no-margin md-button md-ink-ripple layout-align-center-center layout-row')[0] as HTMLButtonElement;
108
    if (assigned(playerElement) && assigned(hideButton)) {
109
        if (hideButton.textContent.includes('HIDE')) {
110
            hidden = false;
111
        } else if (hideButton.textContent.includes('SHOW')) {
112
            hidden = true;
113
        }
114
        playerElement.addEventListener('play', fn => {
115
            if (!hidden) {
116
                hideButton.click();
117
                hidden = !hidden;
118
            }
119
        })
120
        playerElement.addEventListener('pause', fn => {
121
            if (hidden) {
122
                hideButton.click();
123
                hidden = !hidden;
124
            }
125
        })
126
    }
127
}
128
129
function scrollSearchResults(searchRes: Element): void {
130
    let observer = new MutationObserver(mutations => {
131
        let scrollTarget = searchRes.querySelector('md-list-item:not(.animelist-completed):not(.animelist-completed-add)') as HTMLElement;
132
133
        if (assigned(scrollTarget)) {
134
            // The node isn´t in its correct position directly when it´s added so we wait a small bit of time before we start scrolling.
135
            // Also works for long loading lists which need more time to load than we wait (for example One Piece).
136
            window.setTimeout(() => {
137
                // scroll container to episode first
138
                searchRes.scrollTop = scrollTarget.offsetTop;
139
140
                // then scroll page to episode if neccessarry
141
                scrollTarget.scrollIntoView({ behavior: "smooth", block: "nearest" });
142
            }, 500);
143
        }
144
    });
145
146
    observer.observe(searchRes, {
147
        childList: true,
148
    });
149
}
150
151
function findSearchResults(): Element {
152
    return document.querySelector('.search-results .ep-view');
153
}
154